home *** CD-ROM | disk | FTP | other *** search
/ PC World Komputer 2007 December / PCWKCD1207B.iso / Blogowanie poza sfera / Flock 0.9.1.3 stable / flock-0.9.1.3.en-US.win32.exe / flock / components / flockXmlRpc.js < prev    next >
Text File  |  2007-10-12  |  22KB  |  555 lines

  1. // BEGIN FLOCK GPL
  2. // 
  3. // Copyright Flock Inc. 2005-2007
  4. // http://flock.com
  5. // 
  6. // This file may be used under the terms of of the
  7. // GNU General Public License Version 2 or later (the "GPL"),
  8. // http://www.gnu.org/licenses/gpl.html
  9. // 
  10. // Software distributed under the License is distributed on an "AS IS" basis,
  11. // WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
  12. // for the specific language governing rights and limitations under the
  13. // License.
  14. // 
  15. // END FLOCK GPL
  16. //
  17.  
  18. const nsISupports = Components.interfaces.nsISupports;
  19. const nsITimer = Components.interfaces.nsITimer;
  20. const nsITimerCallback = Components.interfaces.nsITimerCallback;
  21. const nsXMLHttpRequest = Components.interfaces.nsXMLHttpRequest;
  22. const TIMER_CONTRACTID = '@mozilla.org/timer;1';
  23. const XMLHTTPREQUEST_CONTRACTID = '@mozilla.org/xmlextras/xmlhttprequest;1';
  24.  
  25.  
  26. function DEBUG(X) { }
  27. //function DEBUG(X) { debug ('flockXmlRpc.js: '+X+'\n'); }
  28.  
  29.  
  30. const Base64 = {
  31.     chars: 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=',
  32.     encode: function (aInput) {
  33.         var output = '';
  34.         while (aInput.length > 0) {
  35.             output += Base64.chars[aInput.charCodeAt(0) >> 2];
  36.             output += Base64.chars[((aInput.charCodeAt(0)&0x03) << 4) | 
  37.                 (aInput.length>1?((aInput.charCodeAt(1)&0xF0) >> 4):0)];
  38.             output += Base64.chars[aInput.length>1?
  39.                 ((aInput.charCodeAt(1)&0x0F)<<2) | 
  40.                 (aInput.length>2?((aInput.charCodeAt(2)&0xC0) >> 6):0):64];
  41.             output += Base64.chars[aInput.length>2?
  42.                 (aInput.charCodeAt(2)&0x3F):64];
  43.             if (aInput.length > 3) {
  44.                 aInput = aInput.substr (3);
  45.             } else {
  46.                 break;
  47.             }
  48.         }
  49.         return output;
  50.     },
  51.     decode: function (aInput) {
  52.         const regexp = new RegExp ('[^'+Base64.chars+']', 'g');
  53.         var output = '';
  54.  
  55.         aInput = aInput.replace (regexp, '');
  56.  
  57.         // FIXME: aInput MUST now be a multiple of four characters long
  58.  
  59.         function sixbits (i) {
  60.             if (i == '=') return 0;
  61.             return Base64.chars.indexOf (i);
  62.         }
  63.  
  64.         while (aInput.length >= 4) {
  65.             output += String.fromCharCode ((sixbits (aInput[0]) << 2) | 
  66.                     (sixbits (aInput[1]) >> 4));
  67.             if (aInput[2] == '=') {
  68.                 break;
  69.             }
  70.             output += String.fromCharCode ((sixbits (aInput[1]) << 4) |
  71.                     (sixbits (aInput[2]) >>2));
  72.             if (aInput[3] == '=') {
  73.                 break;
  74.             }
  75.             output += String.fromCharCode (((sixbits (aInput[2]) << 6) & 0xC0) |
  76.                     sixbits (aInput[3]));
  77.             aInput = aInput.substr (4);
  78.         }
  79.         return output;
  80.     }
  81. }
  82.  
  83. /**
  84. * XXX Thunderbird's W3C-DTF function
  85. *
  86. * Converts a W3C-DTF (subset of ISO 8601) date string to an IETF date
  87. * string.  W3C-DTF is described in this note:
  88. * http://www.w3.org/TR/NOTE-datetime IETF is obtained via the Date
  89. * object's toUTCString() method.  The object's toString() method is
  90. * insufficient because it spells out timezones on Win32
  91. * (f.e. "Pacific Standard Time" instead of "PST"), which Mail doesn't
  92. * grok.  For info, see
  93. * http://lxr.mozilla.org/mozilla/source/js/src/jsdate.c#1526.
  94. */
  95. const HOURS_TO_MINUTES = 60;
  96. const MINUTES_TO_SECONDS = 60;
  97. const SECONDS_TO_MILLISECONDS = 1000;
  98. const MINUTES_TO_MILLISECONDS = MINUTES_TO_SECONDS * SECONDS_TO_MILLISECONDS;
  99. const HOURS_TO_MILLISECONDS = HOURS_TO_MINUTES * MINUTES_TO_MILLISECONDS;
  100.  
  101. function parseIso8601Date(aDateString) {
  102.   var dateString = aDateString;
  103.   dump("Input: "+aDateString+"\n");
  104.   if (!dateString.match('-')) {
  105.     // Fix Wordpress' invalid date format
  106.     // they use date such as 20030530T11:18:50-08:00
  107.     // instead of 2003-05-30T11:18:50-08:00
  108.     var year = dateString.slice(0, 4);
  109.     var month = dateString.slice(4, 6);
  110.     var rest = dateString.slice(6, dateString.length);
  111.     dateString = year + "-" + month + "-" + rest;
  112.   }
  113.  
  114.   var parts = dateString.match(/(\d{4})(-(\d{2,3}))?(-(\d{2}))?(T(\d{2}):(\d{2})(:(\d{2})(\.(\d+))?)?(Z|([+-])(\d{2}):(\d{2}))?)?/);
  115.  
  116.   // Here's an example of a W3C-DTF date string and what .match returns for it.
  117.   //
  118.   // date: 2003-05-30T11:18:50.345-08:00
  119.   // date.match returns array values:
  120.   //
  121.   //   0: 2003-05-30T11:18:50-08:00,
  122.   //   1: 2003,
  123.   //   2: -05,
  124.   //   3: 05,
  125.   //   4: -30,
  126.   //   5: 30,
  127.   //   6: T11:18:50-08:00,
  128.   //   7: 11,
  129.   //   8: 18,
  130.   //   9: :50,
  131.   //   10: 50,
  132.   //   11: .345,
  133.   //   12: 345,
  134.   //   13: -08:00,
  135.   //   14: -,
  136.   //   15: 08,
  137.   //   16: 00
  138.  
  139.   // Create a Date object from the date parts.  Note that the Date
  140.   // object apparently can't deal with empty string parameters in lieu
  141.   // of numbers, so optional values (like hours, minutes, seconds, and
  142.   // milliseconds) must be forced to be numbers.
  143.   var date = new Date(parts[1], parts[3] - 1, parts[5], parts[7] || 0,
  144.     parts[8] || 0, parts[10] || 0, parts[12] || 0);
  145.  
  146.   // We now have a value that the Date object thinks is in the local
  147.   // timezone but which actually represents the date/time in the
  148.   // remote timezone (f.e. the value was "10:00 EST", and we have
  149.   // converted it to "10:00 PST" instead of "07:00 PST").  We need to
  150.   // correct that.  To do so, we're going to add the offset between
  151.   // the remote timezone and UTC (to convert the value to UTC), then
  152.   // add the offset between UTC and the local timezone //(to convert
  153.   // the value to the local timezone).
  154.  
  155.   // Ironically, W3C-DTF gives us the offset between UTC and the
  156.   // remote timezone rather than the other way around, while the
  157.   // getTimezoneOffset() method of a Date object gives us the offset
  158.   // between the local timezone and UTC rather than the other way
  159.   // around.  Both of these are the additive inverse (i.e. -x for x)
  160.   // of what we want, so we have to invert them to use them by
  161.   // multipying by -1 (f.e. if "the offset between UTC and the remote
  162.   // timezone" is -5 hours, then "the offset between the remote
  163.   // timezone and UTC" is -5*-1 = 5 hours).
  164.  
  165.   // Note that if the timezone portion of the date/time string is
  166.   // absent (which violates W3C-DTF, although ISO 8601 allows it), we
  167.   // assume the value to be in UTC.
  168.  
  169.   // The offset between the remote timezone and UTC in milliseconds.
  170.   var remoteToUTCOffset = 0;
  171.   if (parts[13] && parts[13] != "Z") {
  172.     var direction = (parts[14] == "+" ? 1 : -1);
  173.     if (parts[15])
  174.       remoteToUTCOffset += direction * parts[15] * HOURS_TO_MILLISECONDS;
  175.     if (parts[16])
  176.       remoteToUTCOffset += direction * parts[16] * MINUTES_TO_MILLISECONDS;
  177.   }
  178.   remoteToUTCOffset = remoteToUTCOffset * -1; // invert it
  179.  
  180.   // The offset between UTC and the local timezone in milliseconds.
  181.   var UTCToLocalOffset = date.getTimezoneOffset() * MINUTES_TO_MILLISECONDS;
  182.   UTCToLocalOffset = UTCToLocalOffset * -1; // invert it
  183.   date.setTime(date.getTime() + remoteToUTCOffset + UTCToLocalOffset);
  184.  
  185.   return date;
  186. }
  187.  
  188.  
  189. XmlRpcXml = {
  190.     build: function (value) {
  191.         if (value == undefined) {
  192.             return null;
  193.         }
  194.  
  195.         // FIXME: do the next two blocks have the desired effect?
  196.         if (value.QueryInterface) {
  197.             value = value.QueryInterface (flockIXmlRpcValue);
  198.             if (value == null) {
  199.                 return null;
  200.             }
  201.         } else {
  202.             return null;
  203.         }
  204.         try {
  205.             value = value.QueryInterface (flockIXmlRpcValue);
  206.         } catch (e) {
  207.             return value.toString ();
  208.         }
  209.  
  210.         switch (value.XmlRpcType) {
  211.             case flockIXmlRpcValue.TYPE_INT:
  212.                 return <int>{String(value.IntValue)}</int>;
  213.             case flockIXmlRpcValue.TYPE_BOOLEAN:
  214.                 return <boolean>{value.BooleanValue?1:0}</boolean>;
  215.             case flockIXmlRpcValue.TYPE_STRING:
  216.                 return <string>{value.StringValue}</string>;
  217.             case flockIXmlRpcValue.TYPE_DOUBLE:
  218.                 return <double>{String(value.DoubleValue)}</double>;
  219.             case flockIXmlRpcValue.TYPE_DATETIME:
  220.                 var date = new Date ();
  221.                 date.setTime (value.DateTimeValue * 1000);
  222.  
  223.                 var datetime = date.getUTCFullYear();
  224.                 var month = String(date.getUTCMonth() + 1);
  225.                 datetime += (month.length == 1 ?  '0' + month : month);
  226.                 var day = date.getUTCDate();
  227.                 datetime += (day < 10 ? '0' + day : day);
  228.  
  229.                 datetime += 'T';
  230.  
  231.                 var hour = date.getUTCHours();
  232.                 datetime += (hour < 10 ? '0' + hour : hour) + ':';
  233.                 var minutes = date.getUTCMinutes();
  234.                 datetime += (minutes < 10 ? '0' + minutes : minutes) + ':';
  235.                 var seconds = date.getUTCSeconds();
  236.                 datetime += (seconds < 10 ? '0' + seconds : seconds);
  237.  
  238.                 return <dateTime.iso8601>{datetime}</dateTime.iso8601>;
  239.             case flockIXmlRpcValue.TYPE_ARRAY:
  240.                 var elements = value.ArrayElements ({});
  241.                 var array = <array><data/></array>;
  242.                 for (var i=0; i<elements.length; i++) {
  243.                     var q = XmlRpcXml.build (elements[i]);
  244.                     if (q == null) {
  245.                         continue;
  246.                     }
  247.                     array.data.foo = <value>{q}</value>;
  248.                 }
  249.                 return array;
  250.             case flockIXmlRpcValue.TYPE_STRUCT:
  251.                 var keys = value.StructKeys ({});
  252.                 var struct = <struct/>;
  253.                 for (var i in keys) {
  254.                     var q = XmlRpcXml.build (value.StructItem(keys[i]));
  255.                     if (q == null) {
  256.                         continue;
  257.                     }
  258.                     struct.foo = <member>
  259.                                      <name>{keys[i]}</name>
  260.                                      <value>{q}</value>
  261.                                  </member>;
  262.                 }
  263.                 return struct;
  264.             case flockIXmlRpcValue.TYPE_BASE64:
  265.                 return <base64>{Base64.encode(value.Base64Value)}</base64>;
  266.             default:
  267.                 throw 'error building XML';
  268.                 return null;
  269.         }
  270.     },
  271.     parse: function (xml) {
  272.         DEBUG ('XmlRpcXml.parse: '+xml);
  273.         if (xml == undefined) {
  274.             // this is the empty string
  275.             return '';
  276.         }
  277.         if (xml.nodeKind() == 'text') {
  278.             // the default type in string
  279.             return XmlRpcValue.String (xml.toString());
  280.         }
  281.         switch (xml.name().toString()) {
  282.             case 'int':
  283.             case 'i4':
  284.                 return XmlRpcValue.Int (parseInt (xml.text()));
  285.             case 'boolean':
  286.                 return XmlRpcValue.Boolean (parseInt (xml.text()) == 1);
  287.             case 'string':
  288.                 return XmlRpcValue.String (xml.text().toString());
  289.             case 'double':
  290.                 return XmlRpcValue.Double (parseFloat (xml.text()));
  291.             case 'dateTime.iso8601':
  292.                 var val = xml.text().toString();
  293.                 return XmlRpcValue.DateTime (new Date(parseIso8601Date(val)));
  294.             case 'array':
  295.                 var arr = new Array ();
  296.                 for (var i=0; i<xml.data.value.length(); i++) {
  297.                     arr.push (XmlRpcXml.parse(xml.data.value[i].children()[0]));
  298.                 }
  299.                 return XmlRpcValue.Array (arr);
  300.             case 'struct':
  301.                 var struct = new Object ();
  302.                 for (var i=0; i<xml.member.length(); i++) {
  303.                     struct[xml.member[i].name.text()] = 
  304.                         XmlRpcXml.parse(xml.member[i].value.children()[0]);
  305.                 }
  306.                 return XmlRpcValue.Struct (struct);
  307.             case 'base64':
  308.                 return XmlRpcValue.Base64 (Base64.decode (xml.text().toString()));
  309.             default:
  310.                 throw 'error parsing XML';
  311.         }
  312.     }
  313. }
  314.  
  315.  
  316.  
  317. // flockXmlRpcServer object
  318. function flockXmlRpcServerComponent () {
  319.     this.mURL = null;
  320.     this.mTimeout = null;
  321. }
  322.  
  323. flockXmlRpcServerComponent.prototype.QueryInterface = function (aIID) {
  324.     if (aIID.equals (Components.interfaces.flockIXmlRpcServer) ||
  325.             aIID.equals (Components.interfaces.nsISupports)) {
  326.         return this;
  327.     }
  328.  
  329.     throw Components.results.NS_ERROR_NOT_IMPLEMENTED;
  330. }
  331.  
  332. flockXmlRpcServerComponent.prototype.init = function (aURL) {
  333.     DEBUG ('flockXmlRpcServer.init ("'+aURL+'")');
  334.     this.mURL = aURL;
  335.     this.mTimeout = 120*1000;
  336. }
  337.  
  338. flockXmlRpcServerComponent.prototype.call = function (aMethod, aArguments, aListener) {
  339.     //var aOptionalTimeoutInSeconds = 10;
  340.     DEBUG ('flockXmlRpcServer.call ('+aMethod+', '+aArguments+', '+aListener+')\n');
  341.     if (aArguments.XmlRpcType != flockIXmlRpcValue.TYPE_ARRAY) {
  342.         aListener.onError ('the arguments must be in an xmrpc array');
  343.         return;
  344.     }
  345.     var methodCall = <methodCall/>;
  346.     methodCall.methodName = aMethod;
  347.  
  348.     var arguments = aArguments.ArrayElements ({});
  349.     DEBUG ('XMLRPC: got '+arguments.length+' arguments');
  350.     for (var i in arguments) {
  351.         DEBUG ('XMLRPC: adding arg '+XmlRpcXml.build (arguments[i]));
  352.         methodCall.params.param += <param><value>{XmlRpcXml.build (arguments[i])}</value></param>;
  353.     }
  354.     
  355.  
  356.        
  357.     var url = this.mURL;
  358.     var timeout = this.mTimeout;
  359.     var callback = new Object ();
  360.     callback.notify = function (timer) {
  361.         var xhr = Components.classes["@mozilla.org/xmlextras/xmlhttprequest;1"]
  362.             .createInstance (Components.interfaces.nsIXMLHttpRequest);
  363.         xhr.open ('POST', url, true);
  364.         xhr.setRequestHeader ('Content-Type', 'text/xml');
  365.  
  366.         // FIXME: what about charsets?
  367.         // FIXME: should we make this configurable?
  368.         xhr.overrideMimeType ('text/xml'); 
  369.  
  370.         xhr.onreadystatechange = function (aEvent) {
  371.             if (xhr.readyState == 4) {
  372.                 if (!xhr.responseXML) {
  373.                     aListener.onError (xhr.responseText);
  374.                     return;
  375.                 }
  376.  
  377.                 if (xhr.status != 200) {
  378.                     aListener.onError (xhr.statusText);
  379.                     return;
  380.                 }
  381.  
  382.                 //save the state of the XML object directives
  383.                 Orig_XML_ignoreComments  = XML.ignoreComments;
  384.                 Orig_XML_ignoreProcessingInstructions  = XML.ignoreProcessingInstructions;
  385.                 Orig_XML_ignoreWhitespace = XML.ignoreWhitespace;
  386.                 Orig_XML_prettyPrinting = XML.prettyPrinting;
  387.                 Orig_XML_prettyIndent = XML.prettyIndent;
  388.                 //set them to what we need for the parser to behave
  389.                 XML.ignoreComments  = true;
  390.                 XML.ignoreProcessingInstructions  = true;
  391.                 XML.ignoreWhitespace = true;
  392.                 XML.prettyPrinting = false;
  393.                 XML.prettyIndent = false;
  394.                 //var response = new XML (xhr.responseXML);
  395.                 var response = new XML (Components.classes['@mozilla.org/xmlextras/xmlserializer;1'].createInstance (Components.interfaces.nsIDOMSerializer).serializeToString(xhr.responseXML.documentElement));
  396.                 if (response.name() != 'methodResponse' ||
  397.                         !(response.params.param.value.length() == 1 ||
  398.                             response.fault.value.struct.length() == 1)) {
  399.                     aListener.onError ('invalid response XML: '+xhr.responseText);
  400.                     return;
  401.                 }
  402.  
  403.                 if (response.params.param.value.length() == 1) {
  404.                     aListener.onResult (XmlRpcXml.parse (response.params.param.value.children()[0]));
  405.                     //put them back like we found them before we return
  406.                     XML.ignoreComments = Orig_XML_ignoreComments;
  407.                     XML.ignoreProcessingInstructions = Orig_XML_ignoreProcessingInstructions;
  408.                     XML.ignoreWhitespace = Orig_XML_ignoreWhitespace;
  409.                     XML.prettyPrinting = Orig_XML_prettyPrinting;
  410.                     XML.prettyIndent = Orig_XML_prettyIndent;
  411.                     return;
  412.                 }
  413.  
  414.                 var fault = XmlRpcValue.ToJavaScript (
  415.                         XmlRpcXml.parse (response.fault.value.struct));
  416.                 if (fault['faultCode'] == undefined ||
  417.                         fault['faultString'] == undefined) {
  418.                     aListener.onError ('invalid response XML: '+xhr.responseText);
  419.                     //put them back like we found them before we return
  420.                     XML.ignoreComments = Orig_XML_ignoreComments;
  421.                     XML.ignoreProcessingInstructions = Orig_XML_ignoreProcessingInstructions;
  422.                     XML.ignoreWhitespace = Orig_XML_ignoreWhitespace;
  423.                     XML.prettyPrinting = Orig_XML_prettyPrinting;
  424.                     XML.prettyIndent = Orig_XML_prettyIndent;
  425.                     return;
  426.                 }
  427.                 aListener.onFault (fault['faultCode'], fault['faultString']);
  428.                 //put them back like we found them before we return
  429.                 XML.ignoreComments = Orig_XML_ignoreComments;
  430.                 XML.ignoreProcessingInstructions = Orig_XML_ignoreProcessingInstructions;
  431.                 XML.ignoreWhitespace = Orig_XML_ignoreWhitespace;
  432.                 XML.prettyPrinting = Orig_XML_prettyPrinting;
  433.                 XML.prettyIndent = Orig_XML_prettyIndent;
  434.                 return;
  435.             }
  436.         }
  437.         DEBUG ('XMLRPC: sending: '+'<?xml version="1.0"?>\n'+methodCall.toXMLString ());
  438.         DEBUG ('XMLRPC timeout is "' + timeout + '"');
  439.         var timeoutCallback= new Object();
  440.         timeoutCallback.notify = function() {
  441.             DEBUG ('timeoutCallback.notify called');
  442.             if (xhr == null) {
  443.                 DEBUG ("flockXmlRpcServerComponent.prototype.call.timeoutCallback Called with null request!!");
  444.             } else if ((xhr != null) && (xhr.readyState != 4)) {
  445.                 DEBUG ('XMLRPC timed out');
  446.                 //the request still exists and hasn't completed
  447.                 delete xhr['onreadystatechange'];     //Kill the callback function
  448.                 xhr.abort();                          //abort the request
  449.                 aListener.onError ('timeout');          //return an error to the caller
  450.             }
  451.         }
  452.         var timeOutTimer = Components.classes[TIMER_CONTRACTID].createInstance(nsITimer);
  453.         timeOutTimer.initWithCallback (timeoutCallback, timeout, nsITimer.TYPE_ONE_SHOT);
  454.         xhr.send ('<?xml version="1.0"?>\n'+methodCall.toXMLString ());
  455.     }
  456.     var timer = Components.classes[TIMER_CONTRACTID].createInstance(nsITimer);
  457.     timer.initWithCallback (callback, 1, nsITimer.TYPE_ONE_SHOT);
  458. }
  459.  
  460.  
  461.  
  462.  
  463.  
  464. function loadLibrary(aFilename) { // {{{
  465.     var file = Components.classes["@mozilla.org/file/directory_service;1"]
  466.         .getService(Components.interfaces.nsIProperties)
  467.         .get("ComsD", Components.interfaces.nsIFile);
  468.     file.append(aFilename);
  469.  
  470.     var ios = Components.classes["@mozilla.org/network/io-service;1"]
  471.         .getService(Components.interfaces.nsIIOService);
  472.     var fileHandler = ios.getProtocolHandler("file")
  473.         .QueryInterface(Components.interfaces.nsIFileProtocolHandler);
  474.     var spec = fileHandler.getURLSpecFromFile(file);
  475.  
  476.     var scriptLoader = Components.classes["@mozilla.org/moz/jssubscript-loader;1"]
  477.         .getService(Components.interfaces.mozIJSSubScriptLoader);
  478.  
  479.     scriptLoader.loadSubScript(spec);
  480. } // }}}
  481.  
  482. // load the XPCOM library
  483. loadLibrary("flockXPCOMTemplate.js.lib");
  484.  
  485. // load the XMLRPC helper
  486. var loader = Components.classes['@mozilla.org/moz/jssubscript-loader;1']
  487.         .getService(Components.interfaces.mozIJSSubScriptLoader);
  488. loader.loadSubScript("chrome://browser/content/flock/xmlrpc/xmlrpchelper.js");
  489.  
  490. // JavaScript XPCOM Boilerplate
  491. function xpcomModule (aCID, aContractId, aComponentName, aConstructor) {
  492.     this.mCID = Components.ID (aCID);
  493.     this.mContractId = aContractId;
  494.     this.mComponentName = aComponentName;
  495.     this.mConstructor = aConstructor;
  496.     this.mGlobalJavaScript = null;
  497.  
  498.     // factory object
  499.     this.mFactory = {
  500.         constructor: this.mConstructor,
  501.         createInstance: function (aOuter, aIID) {
  502.             if (aOuter != null) {
  503.                 throw Components.results.NS_ERROR_NO_AGGREGATION;
  504.             }
  505.  
  506.             return (new (this.constructor) ()).QueryInterface (aIID);
  507.         }
  508.     };
  509.  
  510. }
  511. xpcomModule.prototype = {
  512.     setGlobalJavaScript: function (aGlobalJavaScript) {
  513.         this.mGlobalJavaScript = aGlobalJavaScript;
  514.     },
  515.  
  516.     // the module should register itself
  517.     registerSelf: function (aCompMgr, aLocation, aLoaderStr, aType) {
  518.         aCompMgr = aCompMgr.QueryInterface (
  519.                 Components.interfaces.nsIComponentRegistrar);
  520.         aCompMgr.registerFactoryLocation (this.mCID, this.mComponentName, 
  521.                 this.mContractId, aLocation, aLoaderStr, aType);
  522.         var catmgr = Components.classes["@mozilla.org/categorymanager;1"]
  523.             .getService (Components.interfaces.nsICategoryManager);
  524.         if (this.mGlobalJavaScript) {
  525.             catmgr.addCategoryEntry ("JavaScript global property",
  526.                     this.mGlobalJavaScript, this.mContractId, true, true);
  527.         }
  528.     },
  529.  
  530.     // get the factory                  
  531.     getClassObject: function (aCompMgr, aCID, aIID) {
  532.         if (!aCID.equals (this.mCID)) {
  533.             throw Components.results.NS_ERROR_NO_INTERFACE;
  534.         }
  535.  
  536.         if (!aIID.equals (Components.interfaces.nsIFactory)) {
  537.             throw Components.results.NS_ERROR_NOT_IMPLEMENTED;
  538.         }
  539.  
  540.         return this.mFactory;
  541.     },
  542.  
  543.     canUnload: function(compMgr) {
  544.         return true;
  545.     }
  546. };
  547.  
  548.  
  549. var module = new xpcomModule ('{709f57f4-a4e4-41bb-a38d-86309fbc4858}',
  550.         '@flock.com/xmlrpc/server;1', 'Flock XML-RPC', 
  551.         flockXmlRpcServerComponent);
  552. function NSGetModule(aCompMgr, aFileSpec) {
  553.     return module;
  554. };
  555.